#include "base_tests.h"

using namespace testing;
using namespace std;
using namespace mili;
using namespace feca;

typedef FullCache<DefaultVectorLoader<Foo> >::Type OneLvlFullCache;
typedef FullCache<FullCache<DefaultVectorLoader<Foo> >::Type>::Type TwoLvlFullCache;

struct FullCacheTest: public ::testing::Test
{
    vector<Foo> v;
    FullCacheTest()
    {
        for (unsigned int i = 0; i < 100; i++)
        {
            insert_into(v, Foo(i));
        }
    }
};

class BarVectorLoader : public VectorLoader<Bar>
{
public:
    typedef BarVectorLoader Loader;
    typedef unsigned int Key;
    typedef Bar CacheableObject;
    BarVectorLoader(vector<Bar>& vector) :
        VectorLoader<Bar>(vector)
    {};
    virtual Bar createEmptyObject(unsigned int k)
    {
        return Bar(k);
    }
};

TEST_F(FullCacheTest, NonDefaultConstructor)
{
    Bar b(1);
    vector<Bar> v;
    insert_into(v, b);
    FullCache<BarVectorLoader>::Type cache(new BarVectorLoader(v));
    Bar* b_ = cache.get(0);
    ASSERT_EQ(b.z, b_->z);
    ASSERT_EQ(1, cache.size());
}

TEST_F(FullCacheTest, Nested)
{
    TwoLvlFullCache cache(new DefaultVectorLoader<Foo>(v));
    for (unsigned int i = 0; i < 100; ++i)
    {
        Foo* f = cache.get(i);
        ASSERT_EQ(i, f->n);
    }
    ASSERT_EQ(100, cache.size());
}

TEST_F(FullCacheTest, IsFullyLoaded)
{
    OneLvlFullCache cache(new DefaultVectorLoader<Foo>(v));
    for (unsigned int i = 0; i < 100; ++i)
    {
        Foo* f = cache.get(i);
        ASSERT_EQ(i, f->n);
    }
    ASSERT_EQ(100, cache.size());
}

TEST_F(FullCacheTest, SetWorks)
{
    OneLvlFullCache cache(new DefaultVectorLoader<Foo>(v));
    Foo f(0);
    cache.insert(static_cast<unsigned int>(1), f);
    ASSERT_TRUE(cache.contains(1));
    ASSERT_FALSE(cache.empty());
}

TEST_F(FullCacheTest, GetWorks)
{
    OneLvlFullCache cache(new DefaultVectorLoader<Foo>(v));
    Foo f1(1);
    cache.insert(1, f1);
    Foo* _f1 = cache.get(1);
    ASSERT_EQ(f1, *_f1);
}
